/*
 * Copyright(C) 2020. Huawei Technologies Co.,Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <vector>
#include <map>
#include <functional>
#include <exception>
#include <memory>
#include <cstdio>
#include <cassert>

#include <unistd.h>
#include <syslog.h>

#include <google/protobuf/message.h>
#include "common/AscendIndex.pb.h"

#include "acl/acl.h"
#include "common/HdcBase.h"
#include "common/RpcUtils.h"
#include "ascenddaemon/impl/AscendAssert.h"
#include "ascenddaemon/impl/AscendException.h"
#include "ascenddaemon/impl/Index.h"
#include "ascenddaemon/impl/IndexIVFPQ.h"
#include "ascenddaemon/impl/IndexIVFSQ.h"
#include "ascenddaemon/impl/IndexIVFFlat.h"
#include "ascenddaemon/impl/IndexFlat.h"
#include "ascenddaemon/impl/IndexSQ.h"
#include "ascenddaemon/impl/IndexPreTransform.h"
#include "ascenddaemon/impl/VectorTransform.h"
#include "ascenddaemon/impl/AuxIndexStructures.h"

using namespace ::ascend;
using namespace ::faiss::ascend;
using ::google::protobuf::Message;

#define LOG_IF_EXCEPT(EXPR) try {                                                                \
        EXPR;                                                            \
    } catch (const AscendException &e) {                                 \
        fprintf(stderr, "AscendException: %s", e.what());                \
        ACL_APP_LOG(ACL_ERROR, "[ascendfaiss] Exception: %s", e.what()); \
        result = CommonResponse_ErrorCode_ERROR;                         \
    } catch (const std::exception &e) {                                  \
        fprintf(stderr, "Exception: %s", e.what());                      \
        ACL_APP_LOG(ACL_ERROR, "[ascendfaiss] Exception: %s", e.what()); \
        result = CommonResponse_ErrorCode_ERROR;                         \
    }

namespace {
bool g_loopEnd = false;
}

// can only be used by one thread at the same time
class HdcServer {
public:
    static HdcServer &GetInstance();
    HdcRpcError Accept(HdcSession *&session);

private:
    explicit HdcServer(int serviceType = HDC_SERVICE_TYPE_RPC);
    ~HdcServer();

    HdcRpcError Init();
    inline bool IsInitialized()
    {
        return initialized;
    }
    inline void SetInitialized(bool init)
    {
        this->initialized = init;
    }

    bool initialized;
    int devId;
    int serviceType;
    HDC_SERVER server;
};

HdcServer::HdcServer(int serviceType) : initialized(false), devId(0), serviceType(serviceType), server(nullptr) {}

HdcServer::~HdcServer()
{
    if (server != nullptr) {
        drvHdcServerDestroy(server);
        server = nullptr;
    }
}

HdcServer &HdcServer::GetInstance()
{
    static HdcServer gServer;

    if (!gServer.IsInitialized()) {
        int ret = gServer.Init();
        if (ret != HDC_RPC_ERROR_NONE) {
            ASCEND_THROW_MSG("Fatal error: hdc server init error, exit!\n");
        } else {
            gServer.SetInitialized(true);
        }
    }

    return gServer;
}

HdcRpcError HdcServer::Init()
{
    int ret = drvHdcServerCreate(devId, serviceType, &server);
    if (ret != DRV_ERROR_NONE) {
        server = nullptr;
        RPC_LOG_ERROR("drvHdcServerCreate failed, ret = %d\n", ret);
        return HDC_RPC_ERROR_ERROR;
    }
    return HDC_RPC_ERROR_NONE;
}

HdcRpcError HdcServer::Accept(HdcSession *&session)
{
    HDC_SESSION sess;
    int ret = drvHdcSessionAccept(server, &sess);
    if (ret != DRV_ERROR_NONE) {
        RPC_LOG_ERROR("drvHdcSessionAccept error, ret = %d\n", ret);
        return HDC_RPC_ERROR_ERROR;
    }

    HdcSession *newSession = new (std::nothrow) HdcSession(0);
    if (newSession == nullptr) {
        return HDC_RPC_ERROR_ERROR;
    }
    ret = newSession->Init(sess);
    if (ret != HDC_RPC_ERROR_NONE) {
        RPC_LOG_ERROR("session init error, ret = %d\n", ret);
        delete newSession;
        return HDC_RPC_ERROR_ERROR;
    }

    session = newSession;
    return HDC_RPC_ERROR_NONE;
}

class SessionHandler {
public:
    explicit SessionHandler(HdcSession *session);
    ~SessionHandler();
    void Handle();

    int CreateIndexIVFPQ(const CreateIndexIVFPQRequest *req, CreateIndexResponse *resp);
    int CreateIndexIVFFlat(const CreateIndexIVFFlatRequest *req, CreateIndexResponse *resp);
    int CreateIndexFlat(const CreateIndexFlatRequest *req, CreateIndexResponse *resp);
    int CreateIndexIVFSQ(const CreateIndexIVFSQRequest *req, CreateIndexResponse *resp);
    int CreateIndexSQ(const CreateIndexSQRequest *req, CreateIndexResponse *resp);
    int CreateIndexPreTransform(const CreateIndexPreTransformRequest *req, CreateIndexResponse *resp);
    int DestroyIndex(const DestroyIndexRequest *req, CommonResponse *resp);

    int IndexIVFUpdateCoarseCent(const IndexIVFUpdateCoarseCentRequest *req, CommonResponse *resp);
    int IndexIVFPQUpdatePQCent(const IndexIVFPQUpdatePQCentRequest *req, CommonResponse *resp);
    int IndexSQUpdateTrainedValue(const IndexSQUpdateTrainedValueRequest *req, CommonResponse *resp);

    int IndexIVFPQAdd(const IndexIVFPQAddRequest *req, CommonResponse *resp);
    int IndexIVFFlatAdd(const IndexIVFFlatAddRequest *req, CommonResponse *resp);
    int IndexFlatAdd(const IndexFlatAddRequest *req, CommonResponse *resp);
    int IndexIVFSQAdd(const IndexIVFSQAddRequest *req, CommonResponse *resp);
    int IndexSQAdd(const IndexSQAddRequest *req, CommonResponse *resp);
    int IndexPreTransformPrepend(const IndexPreTransformPrependRequest *req, CommonResponse *resp);

    int IndexIVFGetListLength(const IndexIVFGetListInfoRequest *req, IndexIVFGetListLengthResponse *resp);
    int IndexIVFGetListCodes(const IndexIVFGetListInfoRequest *req, IndexIVFGetListCodesResponse *resp);
    int IndexFlatGetBaseLength(const IndexFlatGetBaseLengthRequest *req, IndexFlatGetBaseLengthResponse *resp);
    int IndexSQGetBaseLength(const IndexSQGetBaseLengthRequest *req, IndexSQGetBaseLengthResponse *resp);
    int IndexFlatGetBase(const IndexFlatGetBaseRequest *req, IndexFlatGetBaseResponse *resp);
    int IndexSQGetBase(const IndexSQGetBaseRequest *req, IndexSQGetBaseResponse *resp);
    int IndexIVFUpdateNprobe(const IndexIVFUpdateNprobeRequest *req, CommonResponse *resp);
    int IndexSearch(const IndexSearchRequest *req, IndexSearchResponse *resp);
    int IndexRemoveIds(const IndexRemoveIdsRequest *req, IndexRemoveIdsResponse *resp);
    int IndexRemoveRangeIds(const IndexRemoveRangeIdsRequest *req, IndexRemoveIdsResponse *resp);
    int IndexReset(const IndexResetRequest *req, CommonResponse *resp);
    int IndexReserveMemory(const IndexReserveMemRequest *req, CommonResponse *resp);
    int IndexReclaimMemory(const IndexReclaimMemRequest *req, IndexReclaimMemResponse *resp);

    int CreateLinearTransform(const CreateLinearTransformRequest *req, CreateTransformResponse *resp);
    int DestroyTransform(const DestroyTransformRequest *req, CommonResponse *resp);
    int LinearTransformUpdateTrainedValue(const LinearTransformUpdateTrainedValueRequest *req, CommonResponse *resp);

    // for test
    int TestDataIntegrity(const TestDataIntegrityRequest *req, TestDataIntegrityResponse *resp);

private:
    HdcSession *session;
    std::atomic<index_id_t> indexIdCounter;
    std::map<index_id_t, Index *> indices;
    std::atomic<index_id_t> transformsIdCounter;
    std::map<index_id_t, VectorTransform *> transforms;
};

SessionHandler::SessionHandler(HdcSession *session) : session(session), indexIdCounter(0), transformsIdCounter(0) {}

SessionHandler::~SessionHandler()
{
    RPC_LOG_INFO("destruct session handler...\n");

    if (session != nullptr) {
        delete session;
    }

    for (auto &kv : indices) {
        RPC_LOG_INFO("index %d not released, destroy it\n", kv.first);
        delete kv.second;
    }
}

#define HANDLE_RPC(reqType, respType, handleFunc)                         \
    do {                                                                  \
        reqType req;                                                      \
        respType resp;                                                    \
        ret = session->ParseMessage(req, msgLen);                         \
        if (ret == HDC_RPC_ERROR_NONE) {                                  \
            handleFunc(&req, &resp);                                      \
            ret = session->SerializeAndSendMessage(rpcType, false, resp); \
        }                                                                 \
    } while (false)

#define CHECK_AND_ADD_INDEX(index, result, resp, indexIdCounter, indices)    \
    do {                                                                     \
        if (index == nullptr || result == CommonResponse_ErrorCode_ERROR) {  \
            resp->mutable_result()->set_err(CommonResponse_ErrorCode_ERROR); \
            return 0;                                                        \
        }                                                                    \
        index_id_t indexId = indexIdCounter++;                               \
        indices[indexId] = static_cast<Index *>(index);                      \
        resp->set_indexid(indexId);                                          \
        resp->mutable_result()->set_err(result);                             \
    } while (false)

void SessionHandler::Handle()
{
    int ret;
    int rpcType;
    bool isRequest = false;
    int msgLen;

    while (true) {
        ret = session->RecvMessage(rpcType, isRequest, msgLen);
        if (ret != HDC_RPC_ERROR_NONE) {
            RPC_LOG_ERROR("recv msg error\n");
            break;
        }
        RPC_ASSERT(isRequest);
        RPC_ASSERT(msgLen >= 0);

        switch (rpcType) {
            case RPC_CREATE_INDEX_IVFPQ:
                HANDLE_RPC(CreateIndexIVFPQRequest, CreateIndexResponse, CreateIndexIVFPQ);
                break;
            case RPC_CREATE_INDEX_IVFFLAT:
                HANDLE_RPC(CreateIndexIVFFlatRequest, CreateIndexResponse, CreateIndexIVFFlat);
                break;
            case RPC_CREATE_INDEX_FLAT:
                HANDLE_RPC(CreateIndexFlatRequest, CreateIndexResponse, CreateIndexFlat);
                break;
            case RPC_DESTROY_INDEX:
                HANDLE_RPC(DestroyIndexRequest, CommonResponse, DestroyIndex);
                break;
            case RPC_INDEX_IVF_UPDATE_COARSE_CENT:
                HANDLE_RPC(IndexIVFUpdateCoarseCentRequest, CommonResponse, IndexIVFUpdateCoarseCent);
                break;
            case RPC_INDEX_IVFPQ_UPDATE_PQ_CENT:
                HANDLE_RPC(IndexIVFPQUpdatePQCentRequest, CommonResponse, IndexIVFPQUpdatePQCent);
                break;
            case RPC_INDEX_IVF_UPDATE_NPROBE:
                HANDLE_RPC(IndexIVFUpdateNprobeRequest, CommonResponse, IndexIVFUpdateNprobe);
                break;
            case RPC_INDEX_IVFPQ_ADD:
                HANDLE_RPC(IndexIVFPQAddRequest, CommonResponse, IndexIVFPQAdd);
                break;
            case RPC_INDEX_IVFFLAT_ADD:
                HANDLE_RPC(IndexIVFFlatAddRequest, CommonResponse, IndexIVFFlatAdd);
                break;
            case RPC_INDEX_FLAT_ADD:
                HANDLE_RPC(IndexFlatAddRequest, CommonResponse, IndexFlatAdd);
                break;
            case RPC_INDEX_IVF_GET_LIST_LENGTH:
                HANDLE_RPC(IndexIVFGetListInfoRequest, IndexIVFGetListLengthResponse, IndexIVFGetListLength);
                break;
            case RPC_INDEX_IVF_GET_LIST_CODES:
                HANDLE_RPC(IndexIVFGetListInfoRequest, IndexIVFGetListCodesResponse, IndexIVFGetListCodes);
                break;
            case RPC_INDEX_FLAT_GET_BASE:
                HANDLE_RPC(IndexFlatGetBaseRequest, IndexFlatGetBaseResponse, IndexFlatGetBase);
                break;
            case RPC_INDEX_FLAT_GET_BASE_SIZE:
                HANDLE_RPC(IndexFlatGetBaseLengthRequest, IndexFlatGetBaseLengthResponse, IndexFlatGetBaseLength);
                break;
            case RPC_CREATE_INDEX_IVFSQ:
                HANDLE_RPC(CreateIndexIVFSQRequest, CreateIndexResponse, CreateIndexIVFSQ);
                break;
            case RPC_CREATE_INDEX_SQ:
                HANDLE_RPC(CreateIndexSQRequest, CreateIndexResponse, CreateIndexSQ);
                break;
            case RPC_INDEX_SQ_UPDATE_TRAINED_VALUE:
                HANDLE_RPC(IndexSQUpdateTrainedValueRequest, CommonResponse, IndexSQUpdateTrainedValue);
                break;
            case RPC_INDEX_IVFSQ_ADD:
                HANDLE_RPC(IndexIVFSQAddRequest, CommonResponse, IndexIVFSQAdd);
                break;
            case RPC_INDEX_SQ_ADD:
                HANDLE_RPC(IndexSQAddRequest, CommonResponse, IndexSQAdd);
                break;
            case RPC_INDEX_SQ_GET_BASE:
                HANDLE_RPC(IndexSQGetBaseRequest, IndexSQGetBaseResponse, IndexSQGetBase);
                break;
            case RPC_INDEX_SQ_GET_BASE_SIZE:
                HANDLE_RPC(IndexSQGetBaseLengthRequest, IndexSQGetBaseLengthResponse, IndexSQGetBaseLength);
                break;
            case RPC_CREATE_INDEX_PRETRANSFORM:
                HANDLE_RPC(CreateIndexPreTransformRequest, CreateIndexResponse, CreateIndexPreTransform);
                break;
            case RPC_INDEX_PRETRANSFORM_PREPEND:
                HANDLE_RPC(IndexPreTransformPrependRequest, CommonResponse, IndexPreTransformPrepend);
                break;
            case RPC_CREATE_TRANSFORM_LINEAR:
                HANDLE_RPC(CreateLinearTransformRequest, CreateTransformResponse, CreateLinearTransform);
                break;
            case RPC_DESTROY_TRANSFORM:
                HANDLE_RPC(DestroyTransformRequest, CommonResponse, DestroyTransform);
                break;
            case RPC_TRANSFORM_LINEAR_UPDATE_TRAINED_VALUE:
                HANDLE_RPC(LinearTransformUpdateTrainedValueRequest, CommonResponse, LinearTransformUpdateTrainedValue);
                break;
            case RPC_INDEX_SEARCH:
                HANDLE_RPC(IndexSearchRequest, IndexSearchResponse, IndexSearch);
                break;
            case RPC_INDEX_REMOVE_IDS:
                HANDLE_RPC(IndexRemoveIdsRequest, IndexRemoveIdsResponse, IndexRemoveIds);
                break;
            case RPC_INDEX_REMOVE_RANGE_IDS:
                HANDLE_RPC(IndexRemoveRangeIdsRequest, IndexRemoveIdsResponse, IndexRemoveRangeIds);
                break;
            case RPC_INDEX_RESET:
                HANDLE_RPC(IndexResetRequest, CommonResponse, IndexReset);
                break;
            case RPC_INDEX_RESERVE_MEM:
                HANDLE_RPC(IndexReserveMemRequest, CommonResponse, IndexReserveMemory);
                break;
            case RPC_INDEX_RECLAIM_MEM:
                HANDLE_RPC(IndexReclaimMemRequest, IndexReclaimMemResponse, IndexReclaimMemory);
                break;
            case RPC_TEST_DATA_INTEGRITY:
                HANDLE_RPC(TestDataIntegrityRequest, TestDataIntegrityResponse, TestDataIntegrity);
                break;
            default:
                RPC_UNREACHABLE();
        }

        if (ret != HDC_RPC_ERROR_NONE) {
            break;
        }
    }
}

int SessionHandler::CreateIndexIVFPQ(const CreateIndexIVFPQRequest *req, CreateIndexResponse *resp)
{
    RPC_TIME_LOG("CreateIndexIVFPQ, dim=%d, nlist=%d, M=%d, bitsPerCode=%d, nprobe=%d\n", req->dim(), req->nlist(),
        req->subquantizers(), req->bitspercode(), req->nprobe());

    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    IndexIVFPQ *index = nullptr;
    LOG_IF_EXCEPT(
        index = new IndexIVFPQ(req->nlist(), req->dim(), req->subquantizers(), req->bitspercode(), req->nprobe()));
    if (index == nullptr || result == CommonResponse_ErrorCode_ERROR) {
        resp->mutable_result()->set_err(CommonResponse_ErrorCode_ERROR);
        return 0;
    }

    index_id_t indexId = indexIdCounter++;
    indices[indexId] = static_cast<Index *>(index);
    resp->set_indexid(indexId);
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::CreateIndexIVFFlat(const CreateIndexIVFFlatRequest *req, CreateIndexResponse *resp)
{
    RPC_TIME_LOG("CreateIndexIVFFlat, dim=%d, nlist=%d, nprobe=%d\n", req->dim(), req->nlist(), req->nprobe());

    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    IndexIVFFlat *index = nullptr;
    LOG_IF_EXCEPT(index = new IndexIVFFlat(req->nlist(), req->dim(), req->nprobe()));
    if (index == nullptr || result == CommonResponse_ErrorCode_ERROR) {
        resp->mutable_result()->set_err(CommonResponse_ErrorCode_ERROR);
        return 0;
    }

    index_id_t indexId = indexIdCounter++;
    indices[indexId] = static_cast<Index *>(index);
    resp->set_indexid(indexId);
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::CreateIndexFlat(const CreateIndexFlatRequest *req, CreateIndexResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    IndexFlat *index = nullptr;
    LOG_IF_EXCEPT(index = new IndexFlat(req->dim()));
    if (index == nullptr || result == CommonResponse_ErrorCode_ERROR) {
        resp->mutable_result()->set_err(CommonResponse_ErrorCode_ERROR);
        return 0;
    }

    index_id_t indexId = indexIdCounter++;
    indices[indexId] = static_cast<Index *>(index);
    resp->set_indexid(indexId);
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::CreateIndexIVFSQ(const CreateIndexIVFSQRequest *req, CreateIndexResponse *resp)
{
    RPC_TIME_LOG("CreateIndexIVFSQ, dim=%d, nlist=%d, qtype=%d, byResidual=%d, nprobe=%d\n", req->dim(), req->nlist(),
        req->qtype(), req->byresidual(), req->nprobe());

    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    IndexIVFSQ *index = nullptr;
    LOG_IF_EXCEPT(index = new IndexIVFSQ(req->nlist(), req->dim(), req->byresidual(), req->nprobe()));
    CHECK_AND_ADD_INDEX(index, result, resp, indexIdCounter, indices);
    return 0;
}

int SessionHandler::CreateIndexSQ(const CreateIndexSQRequest *req, CreateIndexResponse *resp)
{
    RPC_TIME_LOG("CreateIndexSQ, dim=%d, qtype=%d\n", req->dim(), req->qtype());
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    IndexSQ *index = nullptr;
    LOG_IF_EXCEPT(index = new IndexSQ(req->dim()));
    CHECK_AND_ADD_INDEX(index, result, resp, indexIdCounter, indices);
    return 0;
}

int SessionHandler::CreateIndexPreTransform(const CreateIndexPreTransformRequest *req, CreateIndexResponse *resp)
{
    RPC_TIME_LOG("CreateIndexPreTransform, mainIndexId=%d\n", req->subindexid());
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t subindexId = req->subindexid();
    RPC_ASSERT_FMT(indices.find(subindexId) != indices.end(), "!!!Invalid index id: %d\n", subindexId);
    Index *subindex = indices[subindexId];
    RPC_REQUIRE_NOT_NULL(subindex);

    IndexPreTransform *index = nullptr;
    LOG_IF_EXCEPT(index = new IndexPreTransform(subindex));
    CHECK_AND_ADD_INDEX(index, result, resp, indexIdCounter, indices);
    return 0;
}

int SessionHandler::DestroyIndex(const DestroyIndexRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    RPC_TIME_LOG("DestroyIndex %d\n", indexId);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    LOG_IF_EXCEPT(delete indices[indexId]);
    RPC_TIME_LOG("DestroyIndex end\n");
    indices.erase(indexId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFUpdateCoarseCent(const IndexIVFUpdateCoarseCentRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t total = req->total();
    int32_t dim = req->dim();
    const std::string &data = req->data();
    RPC_TIME_LOG("index %d: UpdateCoarseCent, nlist=%d, dim=%d\n", indexId, total, dim);
    RPC_ASSERT(data.size() == total * dim * sizeof(uint16_t));
    const float16_t *tmp = reinterpret_cast<const float16_t *>(data.data());
    AscendTensor<float16_t, DIMS_2> coarseCent(const_cast<float16_t *>(tmp), { total, dim });

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVF *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    RPC_TIME_LOG("index %d: UpdateCoarseCent actual start\n", indexId);
    LOG_IF_EXCEPT(pIndex->updateCoarseCentroidsData(coarseCent));
    RPC_TIME_LOG("index %d: UpdateCoarseCent end\n", indexId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFPQUpdatePQCent(const IndexIVFPQUpdatePQCentRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t m = req->m();
    int32_t ksub = req->ksub();
    int32_t dsub = req->dsub();
    const std::string &data = req->data();
    RPC_TIME_LOG("index %d: UpdatePQCent, M=%d, ksub=%d, dsub=%d\n", indexId, m, ksub, dsub);
    RPC_ASSERT(data.size() == m * ksub * dsub * sizeof(uint16_t));
    auto tmp = const_cast<char *>(data.data());
    AscendTensor<float16_t, DIMS_2> pqCent(reinterpret_cast<float16_t *>(tmp), { m, ksub * dsub });

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVFPQ *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    RPC_TIME_LOG("index %d: UpdatePQCent actual start\n", indexId);
    LOG_IF_EXCEPT(pIndex->updatePQCentroidsData(pqCent));
    RPC_TIME_LOG("index %d: UpdatePQCent end\n", indexId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexSQUpdateTrainedValue(const IndexSQUpdateTrainedValueRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t dim = req->dim();
    bool isIvfSQ = req->isivfsq();
    const std::string &vmin = req->vmin();
    const std::string &vdiff = req->vdiff();
    RPC_TIME_LOG("index %d: UpdateSQTrainedValue, total=%d, isIvfSQ=%d\n", indexId, dim, isIvfSQ);

    RPC_ASSERT(vmin.size() == dim * sizeof(uint16_t));
    RPC_ASSERT(vdiff.size() == dim * sizeof(uint16_t));
    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);

    auto tmpVmin = const_cast<char *>(vmin.data());
    auto tmpVdiff = const_cast<char *>(vdiff.data());
    AscendTensor<float16_t, DIMS_1> vminTensor(reinterpret_cast<float16_t *>(tmpVmin), { dim });
    AscendTensor<float16_t, DIMS_1> vdiffTensor(reinterpret_cast<float16_t *>(tmpVdiff), { dim });

    if (isIvfSQ) {
        auto pIndex = dynamic_cast<IndexIVFSQ *>(indices[indexId]);
        RPC_REQUIRE_NOT_NULL(pIndex);
        LOG_IF_EXCEPT(pIndex->updateTrainedValue(vminTensor, vdiffTensor));
    } else {
        auto pIndex = dynamic_cast<IndexSQ *>(indices[indexId]);
        RPC_REQUIRE_NOT_NULL(pIndex);
        LOG_IF_EXCEPT(pIndex->updateTrainedValue(vminTensor, vdiffTensor));
    }

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFPQAdd(const IndexIVFPQAddRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t listId = req->listid();
    int32_t codeSize = req->codesize();
    const std::string &codes = req->codes();
    const std::string &ids = req->ids();
    RPC_ASSERT(codes.size() == static_cast<size_t>(n * codeSize));
    RPC_ASSERT(ids.size() == static_cast<size_t>(n * sizeof(uint32_t)));

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVFPQ *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    LOG_IF_EXCEPT(pIndex->addVectors(listId, reinterpret_cast<const uint8_t *>(codes.data()),
        reinterpret_cast<const uint32_t *>(ids.data()), n));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFFlatAdd(const IndexIVFFlatAddRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t listId = req->listid();
    int32_t dim = req->dim();

    const std::string &vectors = req->vectors();
    const std::string &ids = req->ids();
    RPC_ASSERT(vectors.size() == static_cast<size_t>(n * dim) * sizeof(uint16_t));
    RPC_ASSERT(ids.size() == static_cast<size_t>(n * sizeof(uint32_t)));

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVFFlat *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    LOG_IF_EXCEPT(pIndex->addVectors(listId, n, reinterpret_cast<const float16_t *>(vectors.data()),
        reinterpret_cast<const uint32_t *>(ids.data())));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexFlatAdd(const IndexFlatAddRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t dim = req->dim();
    const std::string &vectors = req->vectors();
    ASCEND_THROW_IF_NOT(vectors.size() == static_cast<size_t>(n * dim * sizeof(float16_t)));

    ASCEND_THROW_IF_NOT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexFlat *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);
    auto tmpPtr = reinterpret_cast<const float16_t *>(vectors.data());
    AscendTensor<float16_t, DIMS_2> vec(const_cast<float16_t *>(tmpPtr), { n, dim });
    LOG_IF_EXCEPT(pIndex->addVectors(vec));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFSQAdd(const IndexIVFSQAddRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t listId = req->listid();
    int32_t codeSize = req->codesize();
    const std::string &codes = req->codes();
    const std::string &ids = req->ids();
    const std::string &preCompute = req->precompute();
    RPC_ASSERT(codes.size() == static_cast<size_t>(n * codeSize));
    RPC_ASSERT(ids.size() == static_cast<size_t>(n * sizeof(uint32_t)));
    RPC_ASSERT(preCompute.size() == static_cast<size_t>(n * sizeof(float)));

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);

    auto pIndex = dynamic_cast<IndexIVFSQ *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    LOG_IF_EXCEPT(pIndex->addVectors(listId, n, reinterpret_cast<const uint8_t *>(codes.data()),
        reinterpret_cast<const uint32_t *>(ids.data()), reinterpret_cast<const float *>(preCompute.data())));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexSQAdd(const IndexSQAddRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t dim = req->dim();
    const std::string &data = req->data();
    const std::string &preCompute = req->precompute();
    RPC_ASSERT(data.size() == static_cast<size_t>(n * dim * sizeof(uint8_t)));
    RPC_ASSERT(preCompute.size() == static_cast<size_t>(n * sizeof(float)));

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexSQ *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);
    auto codePtr = reinterpret_cast<const uint8_t *>(data.data());
    auto precompPtre = reinterpret_cast<const float *>(preCompute.data());
    LOG_IF_EXCEPT(pIndex->addVectors(n, codePtr, precompPtre));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexPreTransformPrepend(const IndexPreTransformPrependRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    index_id_t transformId = req->transformid();

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_ASSERT_FMT(transforms.find(transformId) != transforms.end(), "!!!Invalid transform id: %d\n", transformId);
    auto pIndex = dynamic_cast<IndexPreTransform *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    auto pTrans = dynamic_cast<LinearTransform *>(transforms[transformId]);
    RPC_REQUIRE_NOT_NULL(pTrans);
    LOG_IF_EXCEPT(pIndex->prependTransform(pTrans));
    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFGetListLength(const IndexIVFGetListInfoRequest *req, IndexIVFGetListLengthResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t listId = req->listid();

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVF *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    LOG_IF_EXCEPT({
        uint32_t listLen = pIndex->getListLength(listId);
        resp->set_len(listLen);
    });

    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::IndexIVFGetListCodes(const IndexIVFGetListInfoRequest *req, IndexIVFGetListCodesResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t listId = req->listid();

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVF *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);

    LOG_IF_EXCEPT({
        if (pIndex->listVectorsNeedReshaped()) {
            std::vector<unsigned char> codes;
            pIndex->getListVectorsReshaped(listId, codes);
            resp->set_codes(codes.data(), codes.size());
        } else {
            DeviceVector<unsigned char> &codes = pIndex->getListVectors(listId);
            resp->set_codes(codes.data(), codes.size());
        }

        DeviceVector<uint32_t> &ids = pIndex->getListIndices(listId);
        resp->set_ids(ids.data(), ids.size() * sizeof(uint32_t));
    });

    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::IndexFlatGetBaseLength(const IndexFlatGetBaseLengthRequest *req,
    IndexFlatGetBaseLengthResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();

    ASCEND_THROW_IF_NOT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexFlat *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);

    LOG_IF_EXCEPT(resp->set_len(pIndex->getSize()));
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::IndexSQGetBaseLength(const IndexSQGetBaseLengthRequest *req, IndexSQGetBaseLengthResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();

    ASCEND_THROW_IF_NOT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexSQ *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);

    LOG_IF_EXCEPT(resp->set_len(pIndex->getSize()));
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::IndexFlatGetBase(const IndexFlatGetBaseRequest *req, IndexFlatGetBaseResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();

    ASCEND_THROW_IF_NOT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexFlat *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);

    LOG_IF_EXCEPT({
        std::vector<float16_t> vectors;
        pIndex->getVectors(req->offset(), req->num(), vectors);
        resp->set_data(vectors.data(), vectors.size() * sizeof(float16_t));
    });
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::IndexSQGetBase(const IndexSQGetBaseRequest *req, IndexSQGetBaseResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();

    ASCEND_THROW_IF_NOT_FMT(indices.find(indexId) != indices.end(), "Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexSQ *>(indices[indexId]);
    ASCEND_THROW_IF_NOT(pIndex != nullptr);

    LOG_IF_EXCEPT({
        std::vector<uint8_t> vectors;
        pIndex->getVectors(req->offset(), req->num(), vectors);
        resp->set_data(vectors.data(), vectors.size() * sizeof(uint8_t));
    });
    resp->mutable_result()->set_err(result);

    return 0;
}

int SessionHandler::IndexIVFUpdateNprobe(const IndexIVFUpdateNprobeRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t nprobe = req->nprobe();
    RPC_TIME_LOG("index %d update nprobe to %d\n", indexId, nprobe);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    auto pIndex = dynamic_cast<IndexIVF *>(indices[indexId]);
    RPC_REQUIRE_NOT_NULL(pIndex);
    LOG_IF_EXCEPT(pIndex->setNumProbes(nprobe));

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexSearch(const IndexSearchRequest *req, IndexSearchResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    int32_t dim = req->dim();
    int32_t k = req->k();
    const std::string &query = req->query();
    RPC_ASSERT(query.size() == n * dim * sizeof(uint16_t));

    std::vector<uint16_t> distance(n * k);
    std::vector<uint32_t> label(n * k);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d search actual start\n", indexId);
    LOG_IF_EXCEPT(indices[indexId]->search(n, reinterpret_cast<const float16_t *>(query.data()), k,
        reinterpret_cast<float16_t *>(distance.data()), reinterpret_cast<Index::idx_t *>(label.data())));
    RPC_TIME_LOG("index %d search end\n", indexId);

    resp->set_distance(distance.data(), distance.size() * sizeof(uint16_t));
    resp->set_label(label.data(), label.size() * sizeof(uint32_t));
    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::IndexRemoveIds(const IndexRemoveIdsRequest *req, IndexRemoveIdsResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    int32_t n = req->n();
    const std::string &ids = req->ids();
    RPC_TIME_LOG("index %d remove %d ids\n", indexId, n);
    RPC_ASSERT(ids.size() == n * sizeof(IDSelector::idx_t));
    IDSelectorBatch batch(n, reinterpret_cast<const IDSelector::idx_t *>(ids.data()));

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d removeIds actual start\n", indexId);
    LOG_IF_EXCEPT({
        size_t numRemoved = indices[indexId]->removeIds(batch);
        resp->set_num(static_cast<uint32_t>(numRemoved));
    });
    RPC_TIME_LOG("index %d removeIds end\n", indexId);

    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::IndexRemoveRangeIds(const IndexRemoveRangeIdsRequest *req, IndexRemoveIdsResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    uint32_t minId = req->min();
    uint32_t maxId = req->max();
    RPC_TIME_LOG("index %d remove ids range(%d, %d)\n", indexId, minId, maxId);
    IDSelectorRange range(minId, maxId);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d removeRangeIds actual start\n", indexId);
    LOG_IF_EXCEPT({
        size_t numRemoved = indices[indexId]->removeIds(range);
        resp->set_num(static_cast<uint32_t>(numRemoved));
    });
    RPC_TIME_LOG("index %d removeRangeIds end\n", indexId);

    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::IndexReset(const IndexResetRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    RPC_TIME_LOG("index %d reset\n", indexId);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d reset actual start\n", indexId);
    LOG_IF_EXCEPT(indices[indexId]->reset());
    RPC_TIME_LOG("index %d reset end\n", indexId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexReserveMemory(const IndexReserveMemRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    size_t numVec = static_cast<size_t>(req->n());
    RPC_TIME_LOG("index %d reset\n", indexId);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d reserve mem actual start\n", indexId);
    LOG_IF_EXCEPT(indices[indexId]->reserveMemory(numVec));
    RPC_TIME_LOG("index %d reserve mem end\n", indexId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::IndexReclaimMemory(const IndexReclaimMemRequest *req, IndexReclaimMemResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t indexId = req->indexid();
    RPC_TIME_LOG("index %d reset\n", indexId);

    RPC_ASSERT_FMT(indices.find(indexId) != indices.end(), "!!!Invalid index id: %d\n", indexId);
    RPC_TIME_LOG("index %d reclaim mem actual start\n", indexId);
    LOG_IF_EXCEPT({
        size_t reclaimed = indices[indexId]->reclaimMemory();
        resp->set_size(static_cast<uint32_t>(reclaimed));
    });
    RPC_TIME_LOG("index %d reclaim mem end\n", indexId);

    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::CreateLinearTransform(const CreateLinearTransformRequest *req, CreateTransformResponse *resp)
{
    RPC_TIME_LOG("CreateLinearTransform, dimIn=%d, dimOut=%d, haveBias=%d\n", req->dimin(), req->dimout(),
        req->havebias());

    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;

    VectorTransform *transform = nullptr;
    LOG_IF_EXCEPT(transform = new LinearTransform(req->dimin(), req->dimout()));
    if (transform == nullptr || result == CommonResponse_ErrorCode_ERROR) {
        resp->mutable_result()->set_err(CommonResponse_ErrorCode_ERROR);
        return 0;
    }

    index_id_t transformsId = transformsIdCounter++;
    transforms[transformsId] = static_cast<VectorTransform *>(transform);
    resp->set_transformid(transformsId);
    resp->mutable_result()->set_err(result);
    return 0;
}

int SessionHandler::DestroyTransform(const DestroyTransformRequest *req, CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t transformId = req->transformid();
    RPC_TIME_LOG("DestroyTransform %d\n", transformId);

    RPC_ASSERT_FMT(transforms.find(transformId) != transforms.end(), "!!!Invalid transformId id: %d\n", transformId);
    LOG_IF_EXCEPT(delete transforms[transformId]);
    RPC_TIME_LOG("DestroyTransform end\n");
    transforms.erase(transformId);

    resp->set_err(result);
    return 0;
}

int SessionHandler::LinearTransformUpdateTrainedValue(const LinearTransformUpdateTrainedValueRequest *req,
    CommonResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    index_id_t transformsId = req->transformid();
    int32_t dimIn = req->dimin();
    int32_t dimOut = req->dimout();
    const std::string &matrix = req->matrix();
    const std::string &bias = req->bias();
    RPC_TIME_LOG("index %d: UpdateLinearTransformTrainedValue, dimIn=%d, dimOut=%d\n", transformsId, dimIn, dimOut);
    RPC_ASSERT(matrix.size() == dimIn * dimOut * sizeof(uint16_t));
    RPC_ASSERT(bias.size() == 0 || bias.size() == dimOut * sizeof(float));
    auto tmpMatrix = const_cast<char *>(matrix.data());
    auto tmpBias = const_cast<char *>(bias.data());
    AscendTensor<float16_t, DIMS_2> matrixTensor(reinterpret_cast<float16_t *>(tmpMatrix), { dimOut, dimIn });
    AscendTensor<float, DIMS_1> biasTensor(reinterpret_cast<float *>(tmpBias), { dimOut });

    RPC_ASSERT_FMT(transforms.find(transformsId) != transforms.end(), "!!!Invalid transforms id: %d\n", transformsId);
    auto pTransform = dynamic_cast<LinearTransform *>(transforms[transformsId]);
    RPC_REQUIRE_NOT_NULL(pTransform);
    LOG_IF_EXCEPT(pTransform->updateTrainedValue(matrixTensor, biasTensor));

    resp->set_err(result);
    return 0;
}

int SessionHandler::TestDataIntegrity(const TestDataIntegrityRequest *req, TestDataIntegrityResponse *resp)
{
    CommonResponse_ErrorCode result = CommonResponse_ErrorCode_OK;
    const std::string &data = req->data();
    uint8_t checksum = calcChecksum(data.data(), data.size());
    if (req->len() != data.size() || static_cast<uint32_t>(checksum) != req->checksum()) {
        result = CommonResponse_ErrorCode_ERROR;
    }

    resp->mutable_result()->set_err(result);
    if (result == CommonResponse_ErrorCode_OK) {
        resp->set_data(data.data(), data.size());
    }

    return 0;
}

int main()
{
    int ret;

    try {
        HdcServer &server = HdcServer::GetInstance();

        while (!g_loopEnd) {
            RPC_LOG_INFO("start listening...\n");

            HdcSession *sess = nullptr;
            ret = server.Accept(sess);
            if (ret != HDC_RPC_ERROR_NONE) {
                fprintf(stderr, "server accept error\n");
                continue;
            }
            RPC_LOG_INFO("server accept success, start handling session...\n");

            DeviceScope deviceScope;
            SessionHandler handler(sess);
            handler.Handle();
        }
    } catch (std::exception &e) {
        RPC_LOG_ERROR("catch exception: %s\n", e.what());
    }

    return 0;
}
